/*
 * TODO language 
 * Copyright (c) 2010 TODO Team
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef TODO_VM_H
#define TODO_VM_H
#include <stack>
#include "internal.h"
#include "types.h"
#include "modules/module.h"

namespace todo { namespace opcode {
class Opcode;
}}

/**
 * Macro to change the opcode execution order
 */
#define JMP_TO(x) \
	*op_num = x;  \
	return;
	
#define RESULT_P(x) (x)->result->value

/**
 * Opcode handlers arguments
 */
#define HANDLER_ARGS long* op_num, todo::Data* op1, todo::Data* op2, const todo::opcode::Opcode* const opcode
#define HANDLER_ARGS_CALL op_num, op1, op2, opcode

namespace todo { namespace vm {
	
class Engine {
	// Modules
	const TodoModules& modules;
	// Exit code
	int exit_code;
	// Pointer to global scope
	Scope* global_scope;
	// Pointer to current scope
	Scope* current_scope;
	// Scope stack
	static std::stack<Scope*> scopes;
	// Function calling stack
	std::stack<unsigned int> calling;
	// Pointer to function return
	std::stack<ValueResult*> returns;
public:
	typedef void (Engine::*vm_handler)(HANDLER_ARGS);
	
	Engine(const TodoModules&);
	~Engine();

	// Handlers
	void slice(HANDLER_ARGS);
	void subscript(HANDLER_ARGS);
	void print(HANDLER_ARGS);
	void println(HANDLER_ARGS);
	void method_call(HANDLER_ARGS);
	void static_method_call(HANDLER_ARGS);
	void assign(HANDLER_ARGS);
	void declare_var(HANDLER_ARGS);
	void pre_increment(HANDLER_ARGS);
	void pre_decrement(HANDLER_ARGS);
	void pos_increment(HANDLER_ARGS);
	void pos_decrement(HANDLER_ARGS);
	void minus(HANDLER_ARGS);
	void plus(HANDLER_ARGS);
	void div(HANDLER_ARGS);
	void mult(HANDLER_ARGS);
	void mod(HANDLER_ARGS);
	void if_cond(HANDLER_ARGS);
	void jmpz_ex(HANDLER_ARGS);
	void jmp(HANDLER_ARGS);
	void is_equal(HANDLER_ARGS);
	void is_not_equal(HANDLER_ARGS);
	void less(HANDLER_ARGS);
	void greater(HANDLER_ARGS);
	void less_equal(HANDLER_ARGS);
	void greater_equal(HANDLER_ARGS);
	void new_vector(HANDLER_ARGS);
	void vector_add(HANDLER_ARGS);
	void new_map(HANDLER_ARGS);
	void map_add(HANDLER_ARGS);
	void add_func(HANDLER_ARGS);
	void end_func(HANDLER_ARGS);
	void func_call(HANDLER_ARGS);
	void return_stmt(HANDLER_ARGS);
	void exit_stmt(HANDLER_ARGS);
	void xor_expr(HANDLER_ARGS);
	void bw_and_expr(HANDLER_ARGS);
	void shift_right(HANDLER_ARGS);
	void shift_left(HANDLER_ARGS);
	void bw_or_expr(HANDLER_ARGS);
	
	void run(std::vector<todo::opcode::Opcode*>&);
	void shutdown(std::vector<todo::opcode::Opcode*>&);
	void dump_opcode(todo::opcode::Opcode*&) const;
	void pop_scope();
	
	void args_push(ArgList*, const funcargs_t*);
	void register_var(Var*);
	Function* get_func(const std::string&);
	Data* get_var(const std::string&);
	GCValue* get_value(const Data*);
};

}} // todo::vm

#endif // TODO_VM_H
